home *** CD-ROM | disk | FTP | other *** search
/ Enter 2006 September / Enter 09 2006.iso / Internet / SpamExperts Home 1.1 / SpamExperts Home.exe / lib / spamexperts.modules / spambayes / Corpus.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-07-14  |  9.3 KB  |  270 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''Corpus.py - Spambayes corpus management framework.
  5.  
  6. Classes:
  7.     Corpus - a collection of Messages
  8.     ExpiryCorpus - a "young" Corpus
  9.     MessageFactory - creates a Message
  10.  
  11. Abstract:
  12.     A corpus is defined as a set of messages that share some common
  13.     characteristic relative to spamness.  Examples might be spam, ham,
  14.     unsure, or untrained, or "bayes rating between .4 and .6".  A
  15.     corpus is a collection of messages.  Corpus is a dictionary that
  16.     is keyed by the keys of the messages within it.  It is iterable,
  17.     and observable.  Observers are notified when a message is added
  18.     to or removed from the corpus.
  19.  
  20.     Corpus is designed to cache message objects.  By default, it will
  21.     only engage in lazy creation of message objects, keeping those
  22.     objects in memory until the corpus instance itself is destroyed.
  23.     In large corpora, this could consume a large amount of memory.  A
  24.     cacheSize operand is implemented on the constructor, which is used
  25.     to limit the *number* of messages currently loaded into memory.
  26.     The instance variable that implements this cache is
  27.     Corpus.Corpus.msgs, a dictionary.  Access to this variable should
  28.     be through keys(), [key], or using an iterator.  Direct access
  29.     should not be used, as subclasses that manage their cache may use
  30.     this variable very differently.
  31.  
  32.     Iterating Corpus objects is potentially very expensive, as each
  33.     message in the corpus will be brought into memory.  For large
  34.     corpora, this could consume a lot of system resources.
  35.  
  36.     ExpiryCorpus is designed to keep a corpus of file messages that
  37.     are guaranteed to be younger than a given age.  The age is
  38.     specified on the constructor, as a number of seconds in the past.
  39.     If a message file was created before that point in time, the a
  40.     message is deemed to be "old" and thus ignored.  Access to a
  41.     message that is deemed to be old will raise KeyError, which should
  42.     be handled by the corpus user as appropriate.  While iterating,
  43.     KeyError is handled by the iterator, and messages that raise
  44.     KeyError are ignored.
  45.  
  46.     As messages pass their "expiration date," they are eligible for
  47.     removal from the corpus. To remove them properly,
  48.     removeExpiredMessages() should be called.  As messages are removed,
  49.     observers are notified.
  50.  
  51.     ExpiryCorpus function is included into a concrete Corpus through
  52.     multiple inheritance. It must be inherited before any inheritance
  53.     that derives from Corpus.  For example:
  54.  
  55.         class RealCorpus(Corpus)
  56.            ...
  57.  
  58.         class ExpiryRealCorpus(Corpus.ExpiryCorpus, RealCorpus)
  59.            ...
  60.  
  61.     Messages have substance, which is is the textual content of the
  62.     message. They also have a key, which uniquely defines them within
  63.     the corpus.  This framework makes no assumptions about how or if
  64.     messages persist.
  65.  
  66.     MessageFactory is a required factory class, because Corpus is
  67.     designed to do lazy initialization of messages and, as an abstract
  68.     class, must know how to create concrete instances of the correct
  69.     class.
  70.  
  71. To Do:
  72.     o Suggestions?
  73.  
  74. '''
  75. from __future__ import generators
  76. __author__ = 'Tim Stone <tim@fourstonesExpressions.com>'
  77. __credits__ = 'Richie Hindle, Tim Peters, all the spambayes contributors.'
  78.  
  79. try:
  80.     (True, False)
  81. except NameError:
  82.     (True, False) = (1, 0)
  83.     
  84.     def bool(val):
  85.         return not (not val)
  86.  
  87.  
  88. import sys
  89. import time
  90. import types
  91. from spambayes.Options import options
  92. SPAM = True
  93. HAM = False
  94.  
  95. class Corpus:
  96.     '''An observable dictionary of Messages'''
  97.     
  98.     def __init__(self, factory, cacheSize = -1):
  99.         '''Constructor(MessageFactory)'''
  100.         self.msgs = { }
  101.         self.keysInMemory = []
  102.         self.cacheSize = cacheSize
  103.         self.observers = []
  104.         self.factory = factory
  105.  
  106.     
  107.     def addObserver(self, observer):
  108.         '''Register an observer, which should implement
  109.         onAddMessage, onRemoveMessage'''
  110.         self.observers.append(observer)
  111.  
  112.     
  113.     def addMessage(self, message, observer_flags = 0):
  114.         '''Add a Message to this corpus'''
  115.         if options[('globals', 'verbose')]:
  116.             print 'adding message %s to corpus' % message.key()
  117.         
  118.         self.cacheMessage(message)
  119.         for obs in self.observers:
  120.             if hasattr(obs, 'onAddMessage'):
  121.                 obs.onAddMessage(message, observer_flags)
  122.                 continue
  123.         
  124.  
  125.     
  126.     def removeMessage(self, message, observer_flags = 0):
  127.         '''Remove a Message from this corpus'''
  128.         key = message.key()
  129.         if options[('globals', 'verbose')]:
  130.             print 'removing message %s from corpus' % (key,)
  131.         
  132.         self.unCacheMessage(key)
  133.         del self.msgs[key]
  134.         for obs in self.observers:
  135.             if hasattr(obs, 'onRemoveMessage'):
  136.                 obs.onRemoveMessage(message, observer_flags)
  137.                 continue
  138.         
  139.  
  140.     
  141.     def cacheMessage(self, message):
  142.         '''Add a message to the in-memory cache'''
  143.         key = message.key()
  144.         self.msgs[key] = message
  145.         self.keysInMemory.append(key)
  146.         if self.cacheSize > 0:
  147.             if len(self.keysInMemory) > self.cacheSize:
  148.                 keyToFlush = self.keysInMemory[0]
  149.                 self.unCacheMessage(keyToFlush)
  150.             
  151.         
  152.  
  153.     
  154.     def unCacheMessage(self, key):
  155.         '''Remove a message from the in-memory cache'''
  156.         
  157.         try:
  158.             ki = self.keysInMemory.index(key)
  159.         except ValueError:
  160.             pass
  161.  
  162.         del self.keysInMemory[ki]
  163.         self.msgs[key] = None
  164.  
  165.     
  166.     def takeMessage(self, key, fromcorpus, fromCache = False):
  167.         '''Move a Message from another corpus to this corpus'''
  168.         msg = fromcorpus[key]
  169.         msg.load()
  170.         fromcorpus.removeMessage(msg)
  171.         self.addMessage(msg)
  172.  
  173.     
  174.     def get(self, key, default = None):
  175.         if self.msgs.get(key, '') == '':
  176.             return default
  177.         else:
  178.             return self[key]
  179.  
  180.     
  181.     def __getitem__(self, key):
  182.         '''Corpus is a dictionary'''
  183.         amsg = self.msgs.get(key, '')
  184.         if amsg == '':
  185.             raise KeyError(key)
  186.         
  187.         if amsg is None:
  188.             amsg = self.makeMessage(key)
  189.             self.cacheMessage(amsg)
  190.         
  191.         return amsg
  192.  
  193.     
  194.     def keys(self):
  195.         '''Message keys in the Corpus'''
  196.         return self.msgs.keys()
  197.  
  198.     
  199.     def __contains__(self, other):
  200.         return other in self.msgs.values()
  201.  
  202.     
  203.     def __iter__(self):
  204.         '''Corpus is iterable'''
  205.         for key in self.keys():
  206.             yield self[key]
  207.         
  208.  
  209.     
  210.     def __str__(self):
  211.         '''Instance as a printable string'''
  212.         return self.__repr__()
  213.  
  214.     
  215.     def __repr__(self):
  216.         '''Instance as a representative string'''
  217.         raise NotImplementedError
  218.  
  219.     
  220.     def makeMessage(self, key, content = None):
  221.         '''Call the factory to make a message'''
  222.         msg = self.factory.create(key, content)
  223.         return msg
  224.  
  225.  
  226.  
  227. class ExpiryCorpus:
  228.     '''Mixin Class - Corpus of "young" file system artifacts'''
  229.     
  230.     def __init__(self, expireBefore):
  231.         self.expireBefore = expireBefore
  232.         self.expiry_due = time.time()
  233.  
  234.     
  235.     def removeExpiredMessages(self):
  236.         '''Kill expired messages'''
  237.         if time.time() < self.expiry_due:
  238.             return None
  239.         
  240.         self.expiry_due = time.time() + self.expireBefore
  241.         for key in self.keys()[:]:
  242.             msg = self[key]
  243.             timestamp = msg.createTimestamp()
  244.             if timestamp < time.time() - self.expireBefore:
  245.                 if options[('globals', 'verbose')]:
  246.                     print 'message %s has expired' % (msg.key(),)
  247.                 
  248.                 NO_TRAINING_FLAG = NO_TRAINING_FLAG
  249.                 import spambayes.storage
  250.                 self.removeMessage(msg, observer_flags = NO_TRAINING_FLAG)
  251.                 continue
  252.             if timestamp + self.expireBefore < self.expiry_due:
  253.                 self.expiry_due = timestamp + self.expireBefore
  254.                 continue
  255.         
  256.  
  257.  
  258.  
  259. class MessageFactory(object):
  260.     '''Abstract Message Factory'''
  261.     
  262.     def create(self, key, content = None):
  263.         '''Create a message instance'''
  264.         raise NotImplementedError
  265.  
  266.  
  267. if __name__ == '__main__':
  268.     print >>sys.stderr, __doc__
  269.  
  270.